package org.nulldevice.tankshot;

import java.util.ArrayList;

import org.nulldevice.tankshot.entities.Bullet;
import org.nulldevice.tankshot.entities.EnemyTank;
import org.nulldevice.tankshot.entities.Item;
import org.nulldevice.tankshot.entities.Tank;
import org.nulldevice.tankshot.entities.Wall;


// Singleton - holds all game data
public class GameContainer {

	private static GameContainer instance = new GameContainer(); // Instance for
																	// singleton

	protected ArrayList<Tank> tanks;
	protected ArrayList<Bullet> bullets;
	protected ArrayList<Wall> walls;
	protected ArrayList<ArrayList<? extends Item>> items;

	protected ArrayList<Item> itemsToRemove;

	protected GameContainer() {
		// constructor is private, because of singleton
		clear();
	}

	public static GameContainer getInstance() {
		return instance;
	}

	public void addItem(final Item item) {

		if (item instanceof EnemyTank || item instanceof Tank) {
			tanks.add((Tank) item);
		}

		if (item instanceof Wall) {
			walls.add((Wall) item);
		}

		if (item instanceof Bullet) {
			bullets.add((Bullet) item);
		}

	}

	public ArrayList<ArrayList<? extends Item>> getItems() {
		return items;
	}

	public void checkHit(final Item item) {
		// Check if item hits any other Item of the list
		// call the item.hitItem and the hitItem function of the hit item

		for (final ArrayList<? extends Item> list : items) {
			for (int i = 0; i < list.size(); i++) {
				if (isCollisions(item, list.get(i))) {
					item.hitItem(list.get(i));
					((Item) list.get(i)).hitItem(item);
				}
			}
		}
	}

	public boolean isCollisions(final Item item1, final Item item2) {
		// Collisionchecking for all combination of types
		if (item1 == item2) {
			return false;
		}
		if (item1.isAboutToExplode() || item2.isAboutToExplode()) {
			return false;
		}

		// Check collisions between types
		return item1.CollidesWith(item2);

		/*
		 * // bullet - bullet
		 * 
		 * // bullet - wall if ((item1 instanceof Bullet && item2 instanceof
		 * Wall) || (item2 instanceof Bullet && item1 instanceof Wall)){ Bullet
		 * bullet; Wall wall; if (item1 instanceof Bullet){
		 * bullet=(Bullet)item1; wall=(Wall)item2; }else{ bullet=(Bullet)item2;
		 * wall=(Wall)item1; }
		 * 
		 * final int wx = wall.getX(), wy = wall.getY(), wsx = wall.getSizeX(),
		 * wsy = wall.getSizeY();
		 * 
		 * final int wxleft = (wx - wsx / 2), wxright = (wx + wsx / 2), wytop =
		 * (wy - wsy / 2), wybottom = (wy + wsy / 2);
		 * 
		 * if(bullet.getX() >= wxleft && bullet.getX() <= wxright && wytop <=
		 * bullet.getY() && wybottom >= bullet.getY()) {
		 * System.out.println("bullet hit wall"); bullet.hitItem(wall);
		 * wall.hitItem(bullet); return true; } }
		 * 
		 * 
		 * 
		 * 
		 * // Bullet - tank if ((item1 instanceof Bullet && item2 instanceof
		 * Tank) || (item2 instanceof Bullet && item1 instanceof Tank)){ Bullet
		 * bullet; Tank tank; if (item1 instanceof Bullet){
		 * bullet=(Bullet)item1; tank=(Tank)item2; }else{ bullet=(Bullet)item2;
		 * tank=(Tank)item1; } // TODO Add size of bullet for collusion
		 * detection //
		 * System.out.println("Tank: "+tank.getX()+" "+tank.getY()+"\n"
		 * +tank.getBorder().ypoints[0]
		 * +" "+tank.getBorder().ypoints[1]+" "+tank.getBorder().xpoints[0]
		 * +" "+tank.getBorder().xpoints[1] );
		 * if(tank.getBorder().getBounds().contains
		 * (bullet.getX(),bullet.getY())) {
		 * System.out.println("Tank hit by bullet"); bullet.hitItem(tank);
		 * tank.hitItem(bullet); return true; } }
		 * 
		 * // tank - wall if ((item1 instanceof Wall && item2 instanceof Tank)
		 * || (item2 instanceof Wall && item1 instanceof Tank)){ Wall wall; Tank
		 * tank; if (item1 instanceof Wall){ wall=(Wall)item1; tank=(Tank)item2;
		 * }else{ wall=(Wall)item2; tank=(Tank)item1; } final Area a = new
		 * Area(tank.getBorder());
		 * 
		 * // if(a.intersects(wall.getBorder())) {
		 * //System.out.println("Tank Hitting Wall"); // return true; // } }
		 * 
		 * 
		 * // tank - tank if ((item1 instanceof Tank && item2 instanceof Tank)){
		 * // TODO this does not work !!!
		 * if(((Tank)item1).getBorder().getBounds(
		 * ).intersects(((Tank)item2).getBorder().getBounds2D())) {
		 * System.out.println("Tank hitting other Tank"); return true; } }
		 * 
		 * return false;
		 */
	}

	public boolean hitsSolidObject(final Item item) {
		// Check if the item hits a solid object

		for (final Tank tank : tanks) {
			if (isCollisions(tank, item)) {
				return true;
			}
		}
		for (final Wall wall : walls) {
			if (isCollisions(wall, item)) {
				return true;
			}
		}

		return false;
	}

	public ArrayList<Wall> getWalls() {
		return walls;
	}

	public synchronized void removeDestroyedItems() {

		for (final Item item : itemsToRemove) {
			if (item.isDestroyed()) {
				if (item instanceof EnemyTank || item instanceof Tank) {
					tanks.remove(item);
				} else if (item instanceof Wall) {
					walls.remove(item);
				} else if (item instanceof Bullet) {
					bullets.remove(item);
				}
			}
		}
		itemsToRemove.clear();
	}

	public synchronized void addDestroyedItems(
			final ArrayList<Item> destroyedItems) {

		for (final Item item : destroyedItems) {
			if (item.isDestroyed()) {
				itemsToRemove.add(item);
			}
		}
	}

	// clear everything, so we throw everything away
	public void clear() {
		tanks = new ArrayList<Tank>();
		bullets = new ArrayList<Bullet>();
		walls = new ArrayList<Wall>();
		items = new ArrayList<ArrayList<? extends Item>>();
		items.add(tanks);
		items.add(bullets);
		items.add(walls);
		itemsToRemove = new ArrayList<Item>();
	}
}
